{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'\n",
    "import sys\n",
    "sys.path.append('../')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Optional\n",
    "from langchain_deepseek import ChatDeepSeek\n",
    "from pydantic import BaseModel, Field"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 利用LangChain调用模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "J'aime programmer.\n"
     ]
    }
   ],
   "source": [
    "llm = ChatDeepSeek(\n",
    "    model=\"deepseek-chat\",\n",
    "    temperature=0,\n",
    "    max_tokens=None,\n",
    "    timeout=None,\n",
    "    max_retries=2,\n",
    "    api_key=\"sk-e0ebc15c2d124d2cad19536757701fc6\",\n",
    ")\n",
    "\n",
    "messages = [\n",
    "    (\n",
    "        \"system\",\n",
    "        \"您是一个有用的助手，负责将英语翻译成法语。请翻译用户句子。\",\n",
    "    ),\n",
    "    (\"human\", \"我喜欢编程。\"),\n",
    "]\n",
    "resp = llm.invoke(messages)\n",
    "print(resp.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义返回结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Translater(plain_text='你好', translated_text='Bonjour')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Translater(BaseModel):\n",
    "    \"\"\"Joke to tell user.\"\"\"\n",
    "\n",
    "    plain_text: str = Field(description=\"翻译原文\")\n",
    "    translated_text: str = Field(description=\"翻译后的译文\")\n",
    "\n",
    "llm = ChatDeepSeek(\n",
    "    model=\"deepseek-chat\",\n",
    "    temperature=0,\n",
    "    max_tokens=None,\n",
    "    timeout=None,\n",
    "    max_retries=2,\n",
    "    api_key=\"sk-e0ebc15c2d124d2cad19536757701fc6\",\n",
    ")\n",
    "\n",
    "translater_llm = llm.with_structured_output(Translater)\n",
    "\n",
    "resp = translater_llm.invoke(\"请将“你好”翻译成法语\")\n",
    "resp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 流式传输"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当输出类型为字典（TypedDict，JSON Schema）时，就可以从结构化模型中流式输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{}\n",
      "{'setup': ''}\n",
      "{'setup': 'Why'}\n",
      "{'setup': 'Why was'}\n",
      "{'setup': 'Why was the'}\n",
      "{'setup': 'Why was the cat'}\n",
      "{'setup': 'Why was the cat sitting'}\n",
      "{'setup': 'Why was the cat sitting on'}\n",
      "{'setup': 'Why was the cat sitting on the'}\n",
      "{'setup': 'Why was the cat sitting on the computer'}\n",
      "{'setup': 'Why was the cat sitting on the computer?'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': ''}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an eye'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an eye on'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an eye on the'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an eye on the mouse'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an eye on the mouse!'}\n",
      "{'setup': 'Why was the cat sitting on the computer?', 'punchline': 'Because it wanted to keep an eye on the mouse!', 'rating': 8}\n"
     ]
    }
   ],
   "source": [
    "from typing_extensions import Annotated, TypedDict\n",
    "\n",
    "# TypedDict\n",
    "class Joke(TypedDict):\n",
    "    \"\"\"Joke to tell user.\"\"\"\n",
    "\n",
    "    setup: Annotated[str, ..., \"The setup of the joke\"]\n",
    "    punchline: Annotated[str, ..., \"The punchline of the joke\"]\n",
    "    rating: Annotated[Optional[int], None, \"How funny the joke is, from 1 to 10\"]\n",
    "\n",
    "\n",
    "structured_llm = llm.with_structured_output(Joke)\n",
    "\n",
    "llm = ChatDeepSeek(\n",
    "    model=\"deepseek-chat\",\n",
    "    temperature=0,\n",
    "    max_tokens=None,\n",
    "    timeout=None,\n",
    "    max_retries=2,\n",
    "    api_key=\"sk-e0ebc15c2d124d2cad19536757701fc6\",\n",
    ")\n",
    "\n",
    "for chunk in structured_llm.stream(\"Tell me a joke about cats\"):\n",
    "    print(chunk)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### few-shot提示"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 最简单有效的方式就是将实例添加到系统的提示消息中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Translater(plain_text='今晚的月色真美', translated_text='今夜の月はとても美しいです')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "system = \"\"\"你是一名专业的中日语翻译专家\n",
    "你能够判断用户输入是中文（日语），并将其翻译成地道的日语（中文）。返回结果示例如下，其中<plain_text>表示用户输入，<translated_text>表示翻译结果。\n",
    "\n",
    "example_user: 早上好\n",
    "example_assistant: {{\"plain_text\": \"早上好\", \"translated_text\": \"おはようございます\"}}\n",
    "\n",
    "example_user: 拉面\n",
    "example_assistant: {{\"plain_text\": \"拉面\", \"translated_text\": \"ラーメンです\"}}\n",
    "\"\"\"\n",
    "\n",
    "prompt = ChatPromptTemplate([(\"system\", system), (\"human\", \"{input}\")])\n",
    "few_shot_llm = prompt | translater_llm\n",
    "resp = few_shot_llm.invoke({\n",
    "    \"input\": \"今晚的月色真美\",\n",
    "})\n",
    "resp"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
